package hugo.weaving.internal;
import android.os.Build;
import android.os.Looper;
import android.os.Trace;
import android.util.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import java.util.concurrent.TimeUnit;
@Aspect
public class Hugo {
private static volatile boolean enabled = true;
@Pointcut("within(@hugo.weaving.DebugLog *)")
public void withinAnnotatedClass() {}
@Pointcut("execution(!synthetic * *(..)) && withinAnnotatedClass()")
public void methodInsideAnnotatedType() {}
@Pointcut("execution(!synthetic *.new(..)) && withinAnnotatedClass()")
public void constructorInsideAnnotatedType() {}
@Pointcut("execution(@hugo.weaving.DebugLog * *(..)) || methodInsideAnnotatedType()")
public void method() {}
@Pointcut("execution(@hugo.weaving.DebugLog *.new(..)) || constructorInsideAnnotatedType()")
public void constructor() {}
public static void setEnabled(boolean enabled) {
Hugo.enabled = enabled;
}
@Around("method() || constructor()")
public Object logAndExecute(ProceedingJoinPoint joinPoint) throws Throwable {
enterMethod(joinPoint);
long startNanos = System.nanoTime();
Object result = joinPoint.proceed();
long stopNanos = System.nanoTime();
long lengthMillis = TimeUnit.NANOSECONDS.toMillis(stopNanos - startNanos);
exitMethod(joinPoint, result, lengthMillis);
return result;
}
private static void enterMethod(JoinPoint joinPoint) {
if (!enabled) return;
CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
Class<?> cls = codeSignature.getDeclaringType();
String methodName = codeSignature.getName();
String[] parameterNames = codeSignature.getParameterNames();
Object[] parameterValues = joinPoint.getArgs();
StringBuilder builder = new StringBuilder("\u21E2 ");
builder.append(methodName).append('(');
for (int i = 0; i < parameterValues.length; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(parameterNames[i]).append('=');
builder.append(Strings.toString(parameterValues[i]));
}
builder.append(')');
if (Looper.myLooper() != Looper.getMainLooper()) {
builder.append(" [Thread:\"").append(Thread.currentThread().getName()).append("\"]");
}
Log.v(asTag(cls), builder.toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
final String section = builder.toString().substring(2);
Trace.beginSection(section);
}
}
private static void exitMethod(JoinPoint joinPoint, Object result, long lengthMillis) {
if (!enabled) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
Trace.endSection();
}
Signature signature = joinPoint.getSignature();
Class<?> cls = signature.getDeclaringType();
String methodName = signature.getName();
boolean hasReturnType = signature instanceof MethodSignature
&& ((MethodSignature) signature).getReturnType() != void.class;
StringBuilder builder = new StringBuilder("\u21E0 ")
.append(methodName)
.append(" [")
.append(lengthMillis)
.append("ms]");
if (hasReturnType) {
builder.append(" = ");
builder.append(Strings.toString(result));
}
Log.v(asTag(cls), builder.toString());
}
private static String asTag(Class<?> cls) {
if (cls.isAnonymousClass()) {
return asTag(cls.getEnclosingClass());
}
return cls.getSimpleName();
}
}